package com.eva.admin.biz.system;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eva.admin.dao.system.SystemDepartmentMapper;
import com.eva.admin.biz.system.dto.CreateSystemDepartmentDTO;
import com.eva.admin.biz.system.dto.UpdateSystemDepartmentDTO;
import com.eva.framework.common.constants.ResponseStatus;
import com.eva.framework.common.exception.BusinessException;
import com.eva.framework.common.utils.AssertUtil;
import com.eva.framework.common.utils.Utils;
import com.eva.dao.system.model.SystemDepartment;
import com.eva.dao.system.model.SystemUser;
import com.eva.dao.system.model.SystemUserDepartment;
import com.eva.framework.rbac.model.RbacUserInfo;
import com.eva.admin.dao.system.dto.QuerySystemDepartmentDTO;
import com.eva.admin.dao.system.vo.SystemDepartmentVO;
import com.eva.service.system.SystemDepartmentService;
import com.eva.service.system.SystemUserDepartmentService;
import com.eva.service.system.SystemUserService;
import com.eva.framework.rbac.session.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SystemDepartmentBiz {

    @Resource
    private SystemDepartmentService systemDepartmentService;

    @Resource
    private SystemUserService systemUserService;

    @Resource
    private SystemUserDepartmentService systemUserDepartmentService;

    @Resource
    private SystemDepartmentMapper adminSystemDepartmentMapper;

    /**
     * 创建
     *
     * @param dto 创建参数
     */
    @Transactional
    public void create(CreateSystemDepartmentDTO dto) {
        // 验证
        AssertUtil.notEmpty(dto.getName(), "部门名称不能为空");
        // - 如果存在部门编码，则验证部门编码的唯一性
        if (StringUtils.isNotBlank(dto.getCode())) {
            if (systemDepartmentService.exists(new SystemDepartment().setCode(dto.getCode()))) {
                throw new BusinessException(ResponseStatus.DATA_EXISTS, "部门编码已存在");
            }
        }
        // 构建对象
        SystemDepartment newRecord = new SystemDepartment();
        BeanUtils.copyProperties(dto, newRecord);
        // - 存在手机号码时写入摘要
        if (StringUtils.isNotBlank(dto.getMobile())) {
            newRecord.setMobileDigest(Utils.Digest.digestMobile(dto.getMobile()));
        }
        // - 存在邮箱时写入摘要
        if (StringUtils.isNotBlank(dto.getEmail())) {
            newRecord.setEmailDigest(Utils.Digest.digestEmail(dto.getEmail()));
        }
        // 执行创建
        systemDepartmentService.create(newRecord);
    }

    /**
     * 根据主键删除
     *
     * @param id 主键
     */
    @Transactional
    public void deleteById(Integer id) {
        AssertUtil.notEmpty(id, "主键不能为空");
        // 获取子孙部门ID集
        Set<Integer> ids = this.findChildIds(id);
        // 将当前部门一并添加到集合中
        ids.add(id);
        // 执行删除
        systemDepartmentService.deleteByIdInBatch(ids);
    }

    /**
     * 根据主键批量删除
     *
     * @param ids 主键集合
     */
    @Transactional
    public void deleteByIdInBatch(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        for (Integer id : ids) {
            this.deleteById(id);
        }
    }

    /**
     * 修改
     *
     * @param dto 修改参数
     */
    public void updateById(UpdateSystemDepartmentDTO dto) {
        // 验证
        AssertUtil.notNull(dto.getId(), "部门主键不能为空");
        AssertUtil.notEmpty(dto.getName(), "部门名称不能为空");
        // - 如果存在部门编码，则验证部门编码的唯一性
        if (StringUtils.isNotBlank(dto.getCode())) {
            if (systemDepartmentService.exists(SystemDepartment.builder().id(dto.getId()).code(dto.getCode()).build())) {
                throw new BusinessException(ResponseStatus.DATA_EXISTS, "部门编码已存在");
            }
        }
        // 构建对象
        SystemDepartment newRecord = SystemDepartment.builder().build();
        BeanUtils.copyProperties(dto, newRecord);
        // - 存在手机号码时写入摘要
        newRecord.setMobileDigest("");
        if (StringUtils.isNotBlank(dto.getMobile())) {
            newRecord.setMobileDigest(Utils.Digest.digestMobile(dto.getMobile()));
        }
        // - 存在邮箱时写入摘要
        newRecord.setEmailDigest("");
        if (StringUtils.isNotBlank(dto.getEmail())) {
            newRecord.setEmailDigest(Utils.Digest.digestEmail(dto.getEmail()));
        }
        // 执行修改
        systemDepartmentService.updateById(newRecord);
    }

    /**
     * 查询部门列表
     *
     * @return 部门节点数
     */
    public List<SystemDepartmentVO> findAll () {
        // 获取当前登录用户
        RbacUserInfo userInfo = SessionUtil.getLoginUser();
        // 获取部门列表
        List<SystemDepartmentVO> departments = null;
        // - 超级管理员，可查看所有部门
        if (userInfo.getIsSuperAdmin()) {
            QuerySystemDepartmentDTO queryDto = new QuerySystemDepartmentDTO();
            queryDto.setIsSuperAdmin(Boolean.TRUE);
            departments = adminSystemDepartmentMapper.search(queryDto);
        }
        // - 非超级管理员，只能查看自己的部门和子孙部门
        else {
            // 查询用户所在部门
            SystemUserDepartment queryUserDeptDto = new SystemUserDepartment();
            queryUserDeptDto.setUserId(userInfo.getId());
            List<SystemUserDepartment> userDepartments = systemUserDepartmentService.findList(queryUserDeptDto);
            // 获取到部门主键集
            Set<Integer> departmentIds = userDepartments.stream()
                    .map(SystemUserDepartment::getDepartmentId)
                    .collect(Collectors.toSet());
            // 根据部门主键集查询部门列表
            QuerySystemDepartmentDTO queryDto = new QuerySystemDepartmentDTO();
            queryDto.setIds(departmentIds);
            departments = adminSystemDepartmentMapper.search(queryDto);
        }
        if (departments.isEmpty()) {
            return Collections.emptyList();
        }
        // 将部门组装成树
        List<SystemDepartmentVO> allDepartments = adminSystemDepartmentMapper.search(new QuerySystemDepartmentDTO());
        List<SystemDepartmentVO> departmentNodes = new ArrayList<>();
        for (SystemDepartmentVO department : departments) {
            // 查询部门人数
            department.setUserCount(this.count(department.getId()));
            // 查询部门负责人
            SystemUser leader = this.findLeader(department.getId());
            if (leader != null) {
                department.setLeaderId(leader.getId());
                department.setLeaderRealName(leader.getRealName());
            }
            // 填充子部门
            this.fillChildren(department, allDepartments);
            departmentNodes.add(department);
        }
        return departmentNodes;
    }

    /**
     * 统计部门人数
     *
     * @param id 部门ID
     * @return 部门总人数
     */
    public long count (Integer id) {
        // 获取子孙部门ID集
        Set<Integer> departmentIds = this.findChildIds(id);
        // 将当前部门ID添加到ID集，一并进行统计
        departmentIds.add(id);
        // 统计部门人数
        QueryWrapper<SystemUserDepartment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .in(SystemUserDepartment::getDepartmentId, departmentIds)
                .eq(SystemUserDepartment::getDeleted, Boolean.FALSE);
        return systemUserDepartmentService.count(queryWrapper);
    }

    /**
     * 查询负责人
     *
     * @param departmentId 部门ID
     * @return 部门负责人
     */
    public SystemUser findLeader (Integer departmentId) {
        SystemUserDepartment userDepartment =  systemUserDepartmentService.findFirst(new SystemUserDepartment()
                .setDepartmentId(departmentId)
                .setIsLeader(Boolean.TRUE));
        if (userDepartment == null) {
            return null;
        }
        return systemUserService.findById(userDepartment.getUserId());
    }

    /**
     * 查询子孙部门ID集
     *
     * @param departmentId 部门ID
     * @return 子孙部门ID集
     */
    public Set<Integer> findChildIds(Integer departmentId) {
        Set<Integer> pool = new LinkedHashSet<>();
        this.fillChildIds(pool, Collections.singleton(departmentId));
        return pool;
    }

    /**
     * 填充子部门
     *
     * @param pool 子部门集合，用于记录子部门ID
     * @param parentIds 父部门ID集
     */
    private void fillChildIds(Set<Integer> pool, Set<Integer> parentIds) {
        QueryWrapper<SystemDepartment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .in(SystemDepartment::getParentId, parentIds)
                .eq(SystemDepartment::getDeleted, Boolean.FALSE)
        ;
        Set<Integer> ids = systemDepartmentService.findIds(queryWrapper);
        if (ids.size() > 0) {
            pool.addAll(ids);
            this.fillChildIds(pool, ids);
        }
    }

    /**
     * 填充子部门
     *
     * @param parentDepartment 父部门
     * @param allDepartments 所有部门数据
     */
    private void fillChildren (SystemDepartmentVO parentDepartment, List<SystemDepartmentVO> allDepartments) {
        if (parentDepartment.getChildren() == null) {
            parentDepartment.setChildren(new ArrayList<>());
        }
        for (SystemDepartmentVO department : allDepartments) {
            if (!parentDepartment.getId().equals(department.getParentId())) {
                continue;
            }
            // 查询部门人数
            department.setUserCount(systemDepartmentService.count(department.getId()));
            // 查询部门负责人
            SystemUser leader = systemDepartmentService.findLeader(department.getId());
            if (leader != null) {
                department.setLeaderId(leader.getId());
                department.setLeaderRealName(leader.getRealName());
            }
            parentDepartment.getChildren().add(department);
        }
        // 继续填充子部门
        if (parentDepartment.getChildren().size() > 0) {
            for (SystemDepartmentVO node : parentDepartment.getChildren()) {
                this.fillChildren(node, allDepartments);
            }
        }
    }
}
